package org.example;

import java.io.IOException;
import java.lang.ref.PhantomReference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;
import java.lang.ref.WeakReference;



class TestObject{
    @Override
    protected void finalize() throws Throwable{
        System.out.println("finalize");
    }
}

public class ReferenceDemo {
    public static void main(String[] args) throws IOException {
//        strongReference();
//        softReference();
//        weakReference();
        phantomReference();
    }

    public static void strongReference() throws IOException {
        TestObject testObject = new TestObject(); //强引用，在没引用的时候才会回收
        testObject = null;//去掉引用
        System.gc();//
        System.in.read();
    }

    /**
     * VM Options:-Xmx20M
     * 软引用一般用于缓存需求开发
     */
    public static void softReference(){
        SoftReference<byte[]> byteArray = new SoftReference<>(new byte[1024*1024*10]);
        System.out.println(byteArray.get());
        System.gc();
        try{
            Thread.sleep(500);
        }catch (InterruptedException e)
        {
            e.printStackTrace();
        }

        System.out.println(byteArray.get());
        //当出现heap分配不下的时候软引用会被自动清理不需要强制去掉引用。
        byte[] b = new byte[1024*1024*15];
        System.out.println(byteArray.get()); //null
    }

    /**
     * 在触发垃圾回收后弱引用直接被回收，并且不触发finalize操作。
     */
    public static void weakReference(){
        WeakReference<TestObject> w = new WeakReference<>(new TestObject());
        System.out.println(w.get());
        System.gc();
        System.out.println(w.get()); //null

        ThreadLocal<TestObject> tl = new ThreadLocal<>();
        /**
         * Entry extends WeakReference<ThreadLocal<?>>
         */
        tl.set(new TestObject());
        /**
         * private void remove(ThreadLocal<?> key) {
         *             Entry[] tab = table;
         *             int len = tab.length;
         *             int i = key.threadLocalHashCode & (len-1);
         *             for (Entry e = tab[i];
         *                  e != null;
         *                  e = tab[i = nextIndex(i, len)]) {
         *                 if (e.get() == key) {
         *                     e.clear();
         *                    ...
         *                 }
         *             }
         *         }
         *   public void clear() {
         *         this.referent = null;
         *     }
         */
        tl.remove(); //释放value
    }

    /**
     * 幻象引用，也有被说成是虚引用或幽灵引用。幻象引用并不会决定对象的生命周期。即如果一个对象仅持有虚引用，就相当于没有任何引用一样，在任何时候都可能被垃圾回收器回收。
     * 不能通过它访问对象，幻象引用仅仅是提供了一种确保对象被finalize以后，做某些事情的机制（如做所谓的Post-Mortem清理机制），也有人利用幻象引用监控对象的创建和销毁。
     * 另外就是管理堆外内存
     *
     * 虚引用必须和引用队列 （ReferenceQueue）联合使用。当垃圾回收器准备回收一个对象时，如果发现它还有虚引用，就会在回收对象的内存之前，把这个虚引用加入到与之关联的引用队列中。
     */
    public static void phantomReference() throws IOException {
        ReferenceQueue<TestObject> QUEUE = new ReferenceQueue<>();
        PhantomReference<TestObject> p = new PhantomReference<>(new TestObject(), QUEUE);
        System.out.println(p.get());//null
        System.gc();
        System.out.println(p.get()); //null
        System.in.read();
    }
}
